
package com.hlkj.pay.gateway.merchant.impl;
/*
 * Hlpay-Plus aggregate payment system.
 * Copyright (c) 2024-2025 Hlpay Team Copyright has the right of final interpretation.
 */

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.hlkj.framework.common.pojo.CommonResult;
import com.hlkj.framework.extension.executor.ExtensionExecutor;
import com.hlkj.framework.extension.scenario.BizScenario;
import com.hlkj.pay.app.merchant.ext.ChannelMerchantSettleExtPt;
import com.hlkj.pay.app.merchant.ext.MerchantExtConstant;
import com.hlkj.pay.app.merchant.ext.dto.settle.ChannelMerchantAccessSettleContext;
import com.hlkj.pay.dto.merchant.access.MerchantAccessBalanceDto;
import com.hlkj.pay.dto.order.notify.OrderSettleNotifyDto;
import com.hlkj.pay.enums.PayEnums;
import com.hlkj.pay.gateway.merchant.IMerchantAccessSettleGateway;
import com.hlkj.pay.infrastructure.model.merchant.MerchantAccessInfoDO;
import com.hlkj.pay.infrastructure.model.order.OrderSettleDO;
import com.hlkj.pay.infrastructure.model.pay.PayChannelRequestDO;
import com.hlkj.pay.infrastructure.model.pay.ProviderChannelConfigDO;
import com.hlkj.pay.service.merchant.IMerchantApplicationService;
import com.hlkj.pay.service.pay.IPayChannelService;
import com.hlkj.pay.service.pay.IProviderService;

import jodd.util.StringPool;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @author HlpayTeam
 * @date 2024/12/29 17:33
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class MerchantAccessSettleGatewayImpl implements IMerchantAccessSettleGateway {

    private final IProviderService providerService;

    private final ExtensionExecutor extensionExecutor;
    private final IPayChannelService payChannelService;

    private final IMerchantApplicationService merchantApplicationService;

    @Value("${hlkj.pay.barrier:false}")
    private boolean barrier;

    @Value("${hlkj.pay.test:false}")
    private boolean test;

    @Value("${hlkj.domain}")
    private String domain;

    @Override
    public boolean extensionExist(String channelCode) {
        return extensionExecutor.executeExist(ChannelMerchantSettleExtPt.class, BizScenario.valueOf(channelCode));
    }

    @Override
    public CommonResult<MerchantAccessBalanceDto> queryAccessBalance(MerchantAccessInfoDO merchantAccessInfoDO) {
        ChannelMerchantAccessSettleContext context = new ChannelMerchantAccessSettleContext();
        context.setMerchantAccessInfo(merchantAccessInfoDO);
        context.setProviderChannelConfig(providerService.queryConfig(merchantAccessInfoDO.getProviderCode(), merchantAccessInfoDO.getChannelCode()));
        context.setTest(test);
        extensionExecutor.executeVoid(ChannelMerchantSettleExtPt.class, BizScenario.valueOf(merchantAccessInfoDO.getChannelCode()), ex -> ex.queryAccessBalance(context));
        if(!context.isProcessStatus()){
            return CommonResult.error(1,context.getRemark());
        }
        return CommonResult.success(context.getMerchantAccessBalanceDto());

    }

    @Override
    public CommonResult<OrderSettleDO> submitAccessSettle(MerchantAccessInfoDO merchantAccessInfoDO, OrderSettleDO orderSettleDO) {
        ChannelMerchantAccessSettleContext context = new ChannelMerchantAccessSettleContext();
        context.setMerchantAccessInfo(merchantAccessInfoDO);
        context.setOrderSettleDO(orderSettleDO);
        context.setProviderChannelConfig(providerService.queryConfig(merchantAccessInfoDO.getProviderCode(), merchantAccessInfoDO.getChannelCode()));
        context.setTest(test);
        context.setNotifyUrl(domain + MerchantExtConstant.MERCHANT_SETTLE_STATUS_CALLBACK_URL + merchantAccessInfoDO.getChannelCode() + StringPool.SLASH
                + merchantAccessInfoDO.getProviderCode());
        extensionExecutor.executeVoid(ChannelMerchantSettleExtPt.class, BizScenario.valueOf(merchantAccessInfoDO.getChannelCode()), ex -> ex.submitAccessSettle(context));
        PayChannelRequestDO payChannelRequestDO = context.getPayChannelRequestDO();
        if (payChannelRequestDO != null) {
            payChannelRequestDO.setRelationId(merchantAccessInfoDO.getRequestId());
            payChannelRequestDO.setSn(merchantAccessInfoDO.getSn());
            payChannelRequestDO.setChannelCode(merchantAccessInfoDO.getChannelCode());
            payChannelRequestDO.setProviderCode(merchantAccessInfoDO.getProviderCode());
            payChannelService.saveRequest(payChannelRequestDO, PayEnums.CHANNEL_REQUEST_TYPE.MERCHANT_SETTLE);
        }
        if(context.isProcessStatus()){
            return CommonResult.success(context.getUpdateAccessAmountOrderDO());
        }
        
        return CommonResult.error(1,context.getRemark());
    }

    @Override
    public OrderSettleDO queryAccessSettle(MerchantAccessInfoDO merchantAccessInfoDO, OrderSettleDO orderSettleDO) {
        ChannelMerchantAccessSettleContext context = new ChannelMerchantAccessSettleContext();
        context.setMerchantAccessInfo(merchantAccessInfoDO);
        context.setOrderSettleDO(orderSettleDO);
        context.setProviderChannelConfig(providerService.queryConfig(merchantAccessInfoDO.getProviderCode(), merchantAccessInfoDO.getChannelCode()));
        context.setTest(test);
        extensionExecutor.executeVoid(ChannelMerchantSettleExtPt.class, BizScenario.valueOf(merchantAccessInfoDO.getChannelCode()), ex -> ex.queryAccessSettle(context));
        return context.getUpdateAccessAmountOrderDO();
    }

    @Override
    public CommonResult<OrderSettleNotifyDto> orderStatusParse(HttpServletRequest request, ProviderChannelConfigDO providerChannelConfigDO) {
        return extensionExecutor.execute(ChannelMerchantSettleExtPt.class, BizScenario.valueOf(providerChannelConfigDO.getChannelCode()),
                ex -> ex.orderStatusParse(request, providerChannelConfigDO));
    }
}
